/**
 * @file Dofs.h
 * @author Lishijie (lsj1018845759@outlook.com)
 * @brief 
 * @version 0.1
 * @date 2020-11-08
 * 
 * @copyright Copyright (c) 2020
 * 
 */
#ifndef _DOFS_H_
#define _DOFS_H_

#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <initializer_list>
#include <exception>
#include <math.h>
#include "Point.h"

#define TEMPLATE template<Dimension DIM>

/**
 * @brief 自由度类，继承几何点类，新添一个全局编号；
 */
TEMPLATE
class Dofs : public Point<DIM>
{
public:
    /**
     * @brief Construct a new Dofs object
     *        生成一个指定维度自由度，各个分量均为０的自由度，全局编号为０；  
     */
    Dofs();

    /**
     * @brief Construct a new Dofs object by initializer_list in std namespace;
     * 生成一个指定维度自由度，各个分量与initializer_list各分量相同的自由度；
     */
    Dofs(const std::initializer_list<Real>);

    /**
     * @brief Construct a new Dofs object by vector in std namespace;
     *         生成一个指定维度自由度，各个分量与vector各分量相同的自由度；
     */
    Dofs(const std::vector<Real> );

    /**
     * @brief Construct a new Point object by num array in c++/c;
     *        生成一个指定维度自由度，各个分量与数组各分量相同的自由度；
     */
    Dofs(const Real* );

    /**
     * @brief Construct a new Dofs object by initializer_list in std namespace;
     * 生成一个指定维度自由度，各个分量与initializer_list各分量相同的自由度,并且指定全局编号；
     */
    Dofs(const std::initializer_list<Real> ,int);

    /**
     * @brief Construct a new Point object by num array in c++/c;
     *        生成一个指定维度自由度，各个分量与数组各分量相同的自由度,并且指定全局编号；
     */
    Dofs(const std::vector<Real> ,int);

    /**
     * @brief Construct a new Point object by num array in c++/c;
     *        生成一个指定维度自由度，各个分量与数组各分量相同的自由度,并且指定全局编号；
     */
    Dofs(const Real* ,int);

    /**
     * @brief Destroy the Dofs object
     */
    ~Dofs();

    /**
     * @brief Set the Global Index object
     */
    void SetGlobalIndex(const int);

    /**
     * @brief Set and get the Global Index object
     * @return int& 全局编号的引用；
     */
    int& GlobalIndex() {return  _GlbIdx;};

    /**
     * @brief 重载下标运算符operator[]，可以用p[0]表示已经声明的自由度的第一个维度；
     * 
     * @param d 指定维度；
     * @return Real& 返回一个实数类型的应用。
     */
    Real& operator[](const Dimension d) ;

    /**
     * @brief 重载指针运算符，返回
     * 
     * @return Real* 存放自由度坐标的数值；
     */
    Real* operator*(){return Point<DIM>::_value;}

    /**
     * @brief 重载输出运算符operator<<;
     * 
     * @tparam D 该几何点维度；
     * @param os 输出类；
     * @param p 待输出点；
     * @return std::ostream& 输出类的引用；
     */
    template<Dimension D>
    friend std::ostream& operator<<(std::ostream& ,const Dofs<D> &);
private:
    int _GlbIdx;
};

TEMPLATE
Dofs<DIM>::Dofs()
{
//    std::fill(Point<DIM>::_value,Point<DIM>::_value + DIM,static_cast<double>(0));
    _GlbIdx = 0;
};

TEMPLATE
Dofs<DIM>::Dofs(const std::initializer_list<Real> dofs_list)
{
    std::initializer_list<Real>::const_iterator i_begin = dofs_list.begin();
    std::initializer_list<Real>::const_iterator i_end = dofs_list.end();
    std::copy(i_begin,i_end,Point<DIM>::_value);
};

TEMPLATE
Dofs<DIM>::Dofs(const std::vector<Real> dofs_vector)
{
    std::vector<Real>::const_iterator i_begin = dofs_vector.begin();
    std::vector<Real>::const_iterator i_end = dofs_vector.end();
    std::copy(i_begin,i_end,Point<DIM>::_value);
};

TEMPLATE
Dofs<DIM>::Dofs(const Real* array)
{
    std::copy(array,array + DIM,Point<DIM>::_value);
};

TEMPLATE
Dofs<DIM>::Dofs(const std::initializer_list<Real> dofs_list,int gl):_GlbIdx(gl)
{
    std::initializer_list<Real>::const_iterator i_begin = dofs_list.begin();
    std::initializer_list<Real>::const_iterator i_end = dofs_list.end();
    std::copy(i_begin,i_end,Point<DIM>::_value);
};

TEMPLATE
Dofs<DIM>::Dofs(const std::vector<Real> dofs_vector,int gl):_GlbIdx(gl)
{
    std::vector<Real>::const_iterator i_begin = dofs_vector.begin();
    std::vector<Real>::const_iterator i_end = dofs_vector.end();
    std::copy(i_begin,i_end,Point<DIM>::_value);
};

TEMPLATE
Real& Dofs<DIM>::operator[](const Dimension d)
{
    return Point<DIM>::_value[d];

}
TEMPLATE
Dofs<DIM>::Dofs(const Real* array,int gl):_GlbIdx(gl)
{
    std::copy(array,array + DIM,Point<DIM>::_value);
};
TEMPLATE
Dofs<DIM>::~Dofs()
{
};
TEMPLATE
void Dofs<DIM>::SetGlobalIndex(const int gl)
{
    _GlbIdx = gl;
};

template<Dimension D> std::ostream& operator<<(std::ostream& os,const Dofs<D> & dof)
{
    os << dof._GlbIdx << " : " ;
    os << "( ";
    for(Dimension d = 0;d < D - 1 ; d++)
    {
        os << dof.Point<D>::_value[d] << " , ";
    }
    os << dof.Point<D>::_value[D - 1] << " )" << std::endl;
    return os;
}
#undef TEMPLATE
#else
#endif
